package cool.mtc.minghe.service.service.sys.menu.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cool.mtc.core.exception.ServiceException;
import cool.mtc.core.page.PageData;
import cool.mtc.core.util.CollectionUtil;
import cool.mtc.minghe.data.entity.sys.menu.MenuDO;
import cool.mtc.minghe.data.model.sys.menu.dto.MenuDTO;
import cool.mtc.minghe.data.model.sys.menu.dto.MenuDictDTO;
import cool.mtc.minghe.data.model.sys.menu.dto.MenuListDTO;
import cool.mtc.minghe.data.model.sys.menu.dto.MenuTreeSupport;
import cool.mtc.minghe.data.model.sys.menu.form.MenuForm;
import cool.mtc.minghe.data.model.sys.menu.query.MenuQuery;
import cool.mtc.minghe.service.mapper.sys.menu.MenuMapper;
import cool.mtc.minghe.service.service.BaseServiceImpl;
import cool.mtc.minghe.service.service.sys.menu.MenuService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.stream.Collectors;

/**
 * @author 明河
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MenuServiceImpl extends BaseServiceImpl implements MenuService {
    private final MenuMapper menuMapper;

    @Override
    @Transactional
    public long insert(MenuForm form) {
        MenuDO menuDO = form.transToDO();
        if (null != form.getMenuParentId()) {
            MenuDO parentMenuDO = menuMapper.selectById(form.getMenuParentId());
            if (null == parentMenuDO) {
                throw new ServiceException("todo 父级菜单不存在！");
            }
            menuDO.setLevel(parentMenuDO.getLevel() + 1);
        }
        menuMapper.insert(menuDO);
        return menuDO.getId();
    }

    @Override
    @Transactional
    public void update(MenuForm form) {
        MenuDO menuDO = menuMapper.selectById(form.getMenuId());
        if (null == menuDO) {
            throw new ServiceException("todo 当前数据已过期，请刷新后重新！");
        }
        form.updateDO(menuDO);
        menuMapper.updateById(menuDO);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        if (null == id) {
            return;
        }
        MenuDO menuDO = menuMapper.selectById(id);
        if (null == menuDO) {
            return;
        }
        // 检查是否存在下级菜单，如果已存在，不允许删除
        this.handleCheckHasChildData(id);
        menuMapper.deleteById(id);
    }

    private void handleCheckHasChildData(Long id) {
        QueryWrapper<MenuDO> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", id);
        long childCount = menuMapper.selectCount(wrapper);
        if (0 == childCount) {
            return;
        }
        throw new ServiceException("todo 当前数据已存在下级菜单，无法删除！");
    }

    @Override
    public PageData<MenuListDTO> pageList(MenuQuery query) {
        Page<MenuListDTO> pageParam = new Page<>(this.getPage(), this.getPageSize());
        Page<MenuListDTO> pageResult = menuMapper.pageList(pageParam, query);
        return PageData.of(pageResult.getRecords(), pageResult.getTotal());
    }

    @Override
    public MenuDTO info(Long id) {
        if (null == id) {
            return null;
        }
        return menuMapper.getById(id);
    }

    @Override
    public List<MenuListDTO> list(MenuQuery query) {
        List<MenuListDTO> list = menuMapper.list(query);
        int level = this.getMaxLevel(list);
        return this.buildMenuTree(list, new ArrayList<>(), level);
    }

    @Override
    public List<MenuDictDTO> dictList() {
        List<MenuDictDTO> list = menuMapper.listDict();
        int level = this.getMaxLevel(list);
        return this.buildMenuTree(list, new ArrayList<>(), level);
    }

    @Override
    public List<MenuListDTO> currentList() {
        List<MenuListDTO> list = menuMapper.listByUserId(userId());
        int level = this.getMaxLevel(list);
        return this.buildMenuTree(list, new ArrayList<>(), level);
    }

    private <T extends MenuTreeSupport> int getMaxLevel(List<T> list) {
        OptionalInt optionalInt = list.stream().mapToInt(MenuTreeSupport::getLevel).max();
        return optionalInt.isPresent() ? optionalInt.getAsInt() : 0;
    }

    /**
     * 构建菜单树
     */
    private <T extends MenuTreeSupport> List<T> buildMenuTree(List<T> allList, List<T> childList, int level) {
        List<T> parentList = allList.stream().filter(item -> item.getLevel() == level).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(parentList)) {
            return childList;
        }
        parentList.forEach(parent ->
                childList.forEach(child -> {
                    if (parent.getMenuId().equals(child.getMenuParentId())) {
                        parent.getChildren().add(child);
                    }
                })
        );
        return this.buildMenuTree(allList, parentList, level - 1);
    }
}
